package net.jxtz.jxtzos.authentication;


import net.jxtz.jxtzos.authentication.weixin.WechatAuthenticationProvider;
import net.jxtz.jxtzos.authentication.weixin.WechatAuthorizationFilter;
import net.jxtz.jxtzos.mapper.auth.WechatMapper;
import net.jxtz.jxtzos.mapper.redis.RedisMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 *
 * Spring Security 配置类
 *
 * @author a123
 */
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(myAuthenticationProvider)
//                // 新增微信登陆
                .authenticationProvider(wechatAuthenticationProvider);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/**/*.js\",\"/**/*.png\",\"/**/*.ico\",\"/**/*.jpg\", \"/**/*.jpge");
        //swagger api json
        web.ignoring().antMatchers("/swagger-ui.html",
                //用来获取支持的动作
                "/webjars/**",
                //用来获取api-docs的URI
                "/v2/**",
                //安全选项
                "/swagger-resources/**",
                "/csrf");
        web.ignoring().antMatchers("/spider/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors()
                .and()
                .csrf()
                .disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .withObjectPostProcessor(new MyObjectPostProcessor(accessDecisionManager,myFilterInvocationSecurityMetadataSource))
                .and()
                // 禁用session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
//                // 添加微信登陆处理
                .addFilterAt(new WechatAuthorizationFilter(authenticationManager(), redisMapper, wechatMapper), UsernamePasswordAuthenticationFilter.class)
                .addFilterAfter(new JwtAuthorizationFilter(redisMapper), WechatAuthorizationFilter.class)
                // 添加jwt身份校验，添加jwt权限校验器，并且规定在身份校验之后执行
                .addFilterAt(new JwtAuthenticationFilter(authenticationManager(), redisMapper), UsernamePasswordAuthenticationFilter.class)
                .addFilterAfter(new JwtAuthorizationFilter(redisMapper), JwtAuthenticationFilter.class)
                // 自定义退出登陆拦截器
                .logout().logoutUrl("/authentication/logout").addLogoutHandler(new MyLogoutHandler(redisMapper)).logoutSuccessHandler(new MyLogoutSuccessHandler())
                .and()
                // 自定义异常处理
                .exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler()).authenticationEntryPoint(new MyAuthenticationEntryPoint());
    }

    /**
     * 配置全局跨域
     */
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://os.jxtz.net");
        corsConfiguration.addAllowedOrigin("http://localhost:8080");
        corsConfiguration.addAllowedOrigin("http://localhost:8081");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }


    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }

    @Bean
    public AntPathMatcher antPathMatcher(){
        return new AntPathMatcher();
    }

    @Bean
    BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    private MyAuthenticationProvider myAuthenticationProvider;

    private WechatAuthenticationProvider wechatAuthenticationProvider;

    private RedisMapper redisMapper;

    private MyAccessDecisionManager accessDecisionManager;

    private MyFilterInvocationSecurityMetadataSource myFilterInvocationSecurityMetadataSource;

    private WechatMapper wechatMapper;

    @Autowired
    public void setWechatMapper(WechatMapper wechatMapper){
        this.wechatMapper = wechatMapper;
    }

    @Autowired
    private void setWechatAuthenticationProvider(WechatAuthenticationProvider wechatAuthenticationProvider){
        this.wechatAuthenticationProvider = wechatAuthenticationProvider;
    }

    @Autowired
    public void setRedisMapper(RedisMapper redisMapper){
        this.redisMapper = redisMapper;
    }

    @Autowired
    public void setMyAuthenticationProvider(MyAuthenticationProvider myAuthenticationProvider){
        this.myAuthenticationProvider = myAuthenticationProvider;
    }

    @Autowired
    public void setAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager){
        this.accessDecisionManager = myAccessDecisionManager;
    }

    @Autowired
    public void setMyFilterInvocationSecurityMetadataSource(MyFilterInvocationSecurityMetadataSource myFilterInvocationSecurityMetadataSource){
        this.myFilterInvocationSecurityMetadataSource = myFilterInvocationSecurityMetadataSource;
    }
}
